package org.atlantis.grosbeak.depot.weaver;

import org.atlantis.grosbeak.depot.DepotMaker;
import org.atlantis.grosbeak.depot.EventTrigger;
import org.atlantis.grosbeak.depot.ObjectWeaver;
import org.atlantis.grosbeak.depot.proxy.ValueProxy;
import org.atlantis.grosbeak.lang.fruit.Fruiting;

/**
 * 对象构造器。用来构造非单态的对象。<br>
 * 构建顺序是：
 * <ol>
 * <li>获取对象实例化所需要的构造方法参数（参数可有可无）。</li>
 * <li>通过构造方法参数来实例化对象。</li>
 * <li>给实例化好后的对象的相关字段注入值。</li>
 * <li>触发对象的create事件（如果用户定义了create事件的话）。</li>
 * </ol>
 * 
 * @author <a href="mailto:seenoevil.cn@gmail.com">SeeNoEvil</a>
 * 
 */
public class DynamicWeaver implements ObjectWeaver {

	// 创建对象时，会触发create事件
	protected EventTrigger<Object> create;
	// 销毁对象时，会触发destroy事件
	protected EventTrigger<Object> destroy;
	private Fruiting<?> fruiting;
	private ValueProxy[] args;
	private FieldInjector[] fields;

	/**
	 * 设定对象的create事件。
	 * 
	 * @param create
	 *            create事件。
	 */
	public void setCreate(EventTrigger<Object> create) {
		this.create = create;
	}

	/**
	 * 设定对象的destroy事件。
	 * 
	 * @param destroy
	 *            destroy事件。
	 */
	public void setDestroy(EventTrigger<Object> destroy) {
		this.destroy = destroy;
	}

	/**
	 * 设定对象的初始化方式。
	 * 
	 * @param fruiting
	 *            对象的初始化方式。
	 * @see org.atlantis.grosbeak.lang.fruit.Fruiting
	 */
	public void setFruiting(Fruiting<?> fruiting) {
		this.fruiting = fruiting;
	}

	/**
	 * 设定对象构造方法所需要的参数。
	 * 
	 * @param args
	 *            对象构造方法所需要的参数。
	 */
	public void setArgs(ValueProxy[] args) {
		this.args = args;
	}

	/**
	 * 设定对象相关字段的注入方式。
	 * 
	 * @param fields
	 *            对象相关字段的注入方式。
	 */
	public void setFields(FieldInjector[] fields) {
		this.fields = fields;
	}

	/**
	 * 销毁对象。这里是空实现，因为非单态的对象的销毁不由程序控制。
	 */
	public void destroy() {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.atlantis.grosbeak.depot.ObjectWeaver#weave(org.atlantis.grosbeak.
	 * depot.DepotMaker)
	 */
	public Object weave(DepotMaker maker) {
		// 准备构造方法的参数
		Object[] args = new Object[this.args.length];
		for (int i = 0; i < args.length; i++) {
			args[i] = this.args[i].get(maker);
		}

		// 实例化对象
		Object obj = fruiting.fruit(args);

		// 设置各个字段的值
		for (FieldInjector fi : fields) {
			fi.inject(maker, obj);
		}

		// 触发创建事件
		if (null != create)
			create.trigger(obj);
		return obj;
	}
}
